/*
 * CacheTask.cpp
 *
 *  Created on: 09.12.2012
 *      Author: zheka
 */

#include "CacheTask.hpp"
#include "io/Client.hpp"
#include "util/Log.hpp"
#include "util/ProxyException.hpp"
#include "util/StringUtils.hpp"
#include <limits>
CacheTask::CacheTask(CacheEntry * cacheEntry, const HttpRequest & request) :
		cacheEntry(cacheEntry), written(0), state(STATE_READ_HEADER), readChunk(
				false), readCount(0) {
	Client client(request.getConnectionInfo());
	client.connect();

	setFileDiscriptor(client.getSocketFileDescriptor());

	requestData = request.toString();
	Log::v(
			"[CacheTask] [" + StringUtils::toString(getFileDiscriptor()) + "] "
					+ request.getHttpQuery());
	query = request.getHttpQuery();

}

void CacheTask::onInit(Context & context) {
	context.enableWrite();
	Log::v("[CacheTask] enable write");
}
// TODO: onDestroy
#include <cstdio>
void CacheTask::onRead(Context & context) {
	checkSocket();
	if (state == STATE_READ_HEADER) {
		const std::string & buffer = read(1);
		if (buffer.length() > 0) {
			if (buffer == "\n") {
//				Log::v("On new line [" + data + "]");
				bool result = parser.putLine(data);
				if (!result) {
					HttpResponse response = parser.getHttpResponse();

					contentLength = std::numeric_limits<int>::max();
					contentLength = 0;
					try {
						contentLength = response.getContentLength();
					} catch (...) {
					}



					chuncked = response.getHeader("Transfer-Encoding")
							== "chunked";

					Log::v(response.toString());
					Log::v("[CacheTask] [" + StringUtils::toString(getFileDiscriptor()) + "] CONTENT - LENGTH  =  "+StringUtils::toString(contentLength));
					// TODO: check http code (200 or error)


					if(response.getResponseCode() != "200"){
						cacheEntry->disposable = true;
					}

					cacheEntry->add(response.toString());

					state = STATE_READ_DATA;
				/*	if(contentLength == 0) {
						cacheEntry->finish();
						context.unregister();
											state = STATE_FINISHED;
										}*/
				}
				data.clear();

			} else {
				data += buffer;
			}
		} else {

			throw ProxyException("[CacheTask] End of file!");

		}
	}

	if (state == STATE_READ_DATA) {

 		if (chuncked) {

			if (!readChunk) {
				const std::string & buffer = read(1);
				if (buffer.length() > 0) {
					if (buffer == "\n") {
						cacheEntry->add(lineBuffer + "\n");
						std::string sss = "0x" + lineBuffer;
						//std::stringstream ss("0x" + lineBuffer);
						//ss >> chunkSize;
						sscanf(sss.c_str(), "%x", &chunkSize);
//						Log::v("ChunkSize="+StringUtils::toString(chunkSize)+ " lb="+lineBuffer);
						if (chunkSize == 0) {

							context.unregister();
							state = STATE_FINISHED;
							cacheEntry->add("\r\n");
							cacheEntry->finish();
						} else {
							chunkSize += 2; // read cr lf
							readChunk = true;
						}
						lineBuffer.clear();
					} else {
						lineBuffer += buffer;
					}
				} else {
					cacheEntry->finish();
					context.unregister();
					state = STATE_FINISHED;
				}
			} else {
				int bufferSize = ((chunkSize - 1024) > 0) ? 1024 : chunkSize;
				const std::string & buffer = read(bufferSize);
			//	Log::v("read="+StringUtils::toString(bufferSize));
				if (chunkSize != 0) {
					if (buffer.length() > 0) {
						chunkSize -= buffer.length();
						cacheEntry->add(buffer);
					} else {
						cacheEntry->finish();
						context.unregister();
						state = STATE_FINISHED;
					}
				} else {
					readChunk = false;
				}
			}
		} else {
//		Log::v(StringUtils::toString(getFileDiscriptor())+" Attempt to read =  readCount="+StringUtils::toString(readCount)+" of "+StringUtils::toString(contentLength) );
			if (readCount < contentLength) {

				const std::string & buffer = read(2048*2);
				if (buffer.length() > 0) {
					readCount += buffer.length();
					cacheEntry->add(buffer);
					if(readCount == contentLength ) {
						cacheEntry->finish();

											context.unregister();
					}
				} else {
					cacheEntry->finish();

					context.unregister();
					Log::v(
							"[CacheTask] UNREGISTER ["
									+ StringUtils::toString(getFileDiscriptor())
									+ "]");
					state = STATE_FINISHED;
				}
			} else {
				cacheEntry->finish();

				context.unregister();
				Log::v(
						"[CacheTask] UNREGISTER ["
								+ StringUtils::toString(getFileDiscriptor())
								+ "]");
				state = STATE_FINISHED;
			}
		}
 	}


//	const std::string & buffer = read(100);
//	if (buffer.length() == 0) {
//		context.unregister();
//		Log::v("[CacheTask] STOPP!");
//		return;
//	}
//	Log::v("[CacheTask] Read = " + buffer);
}
void CacheTask::onWrite(Context & context) {
	checkSocket();
	if (written < requestData.size()) {
		written += write(requestData, written);
	} else {
		context.disableWrite();
		context.enableRead();
		Log::v("[CacheTask] Enable read");
	}
}

std::string CacheTask::toString() {
	return "[CacheTask] " +(chuncked?StringUtils::toString(cacheEntry->data.length()-parser.getHttpResponse().toString().length()) : StringUtils::toString(cacheEntry->data.length()-parser.getHttpResponse().toString().length()) +" of "+StringUtils::toString(contentLength) )+ Task::toString() + " " + query;
}

